import { Button, EventTouch, Node } from "cc";
import { EngineConfig } from "./EngineConfig";
import DateUtil from "./DateUtil";

export class EventManager {

    public static instance: EventManager = new EventManager();
    public handlers = {};


    private static lastClickTime: number = 0

    public on(eventName: string, handler: Function, target: any) {
        let handlerList = this.handlers[eventName];
        if (!handlerList) {
            handlerList = [];
            this.handlers[eventName] = handlerList;
        }

        for (let i = 0; i < handlerList.length; i++) {
            if (!handlerList[i]) {
                handlerList[i].handler = handler;
                handlerList[i].target = target;
                return i;
            }
        }
        handlerList.push({ handler: handler, target: target });
        return handlerList.length;
    };

    public dispatch(eventName: string, ...restOfName: any[]) {
        let handlerList = this.handlers[eventName];
        if (!handlerList) {
            return;
        }
        // for (let i = 0; i < handlerList.length; i++) {
        for (let i = handlerList.length - 1; i >= 0; i--) {
            let handler = handlerList[i].handler;
            let target = handlerList[i].target;
            if (handler) {
                try {
                    if (target) {
                        handler.call(target, ...restOfName)
                    } else {
                        handler.call(...restOfName)
                    }
                } catch (e) {
                    console.error(e);
                }
            }
        }
    }

    public dispatchOnce(eventName: string, ...restOfName: any[]) {
        let handlerList = this.handlers[eventName];
        if (!handlerList) {
            return;
        }
        // for (let i = 0; i < handlerList.length; i++) {
        for (let i = handlerList.length - 1; i >= 0; i--) {
            let handler = handlerList[i].handler;
            let target = handlerList[i].target;
            if (handler) {
                try {
                    if (target) {
                        handler.call(target, ...restOfName)
                    } else {
                        handler.call(...restOfName)
                    }
                    break;
                } catch (e) {
                    console.error(e);
                }
            }
        }
    }

    public off(eventName: string, handler: Function, target: any) {
        let handlerList = this.handlers[eventName];
        if (!handlerList) {
            return;
        }

        for (let i = 0; i < handlerList.length; i++) {
            let oldHandler = handlerList[i].handler;
            let oldTarget = handlerList[i].target;
            if (oldHandler === handler && oldTarget === target) {
                handlerList.splice(i, 1);
                break;
            }
        }
    }

    public clear(target: any) {
        for (let eventName in this.handlers) {
            let handlerList = this.handlers[eventName];
            for (var i = 0; i < handlerList.length; i++) {
                var oldTarget = handlerList[i].target;
                if (oldTarget === target) {
                    handlerList.splice(i, 1);
                }
            }
        }
    }

    public clearAll() {
        this.handlers = {}
    }

    public static onAddEvent(btnDisplay: Node, callback: Function,
        transition: number = Button.Transition.SCALE, zoneScale: number = 0.95) {
        let btn: Button = btnDisplay.getComponent(Button)
        if (!btn) {
            btn = btnDisplay.addComponent(Button);
            btn.transition = transition;
            btn.zoomScale = zoneScale
        }
        btnDisplay.targetOff(btnDisplay);
        btnDisplay.on(Node.EventType.TOUCH_END, (event: EventTouch) => {
            if (btn.enabled) {
                if (DateUtil.now() - this.lastClickTime >= 100) {
                    this.lastClickTime = DateUtil.now()
                    EventManager.instance.dispatch(EngineConfig.Event_Type.Event_Click, event)
                    callback && callback();
                }
            }
        }, btnDisplay);
    }

    public removeBtnEvent(objectNode: Node) {
        let button: Button = objectNode.getComponent(Button)
        if (button) {
            button.destroy()
        }
    }

    public removeBtnEffect(objectNode: Node) {
        let b: Button = objectNode.getComponent(Button);
        b.transition = Button.Transition.NONE;
    }

}
